/* Copyright (c) 2022 Peigen.info. All rights reserved. */

package com.gitee.peigenlpy.mica.client.integration;


import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.gitee.peigenlpy.mica.client.MqttClientCustomizer;
import com.gitee.peigenlpy.mica.client.MqttClientSubscribe;
import com.gitee.peigenlpy.mica.client.MqttClientTemplate;
import com.gitee.peigenlpy.mica.client.config.MqttClientConfiguration;
import com.gitee.peigenlpy.mica.client.config.MqttClientProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.core.client.IMqttClientConnectListener;
import net.dreamlu.iot.mqtt.core.client.IMqttClientMessageListener;
import net.dreamlu.iot.mqtt.core.client.IMqttClientSession;
import net.dreamlu.iot.mqtt.core.client.MqttClientCreator;
import net.dreamlu.iot.mqtt.core.util.TopicUtil;
import org.noear.solon.Solon;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.BeanExtractor;
import org.noear.solon.core.BeanWrap;
import org.noear.solon.core.Plugin;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

/**
 * <b>(MqttClientPluginImpl)</b>
 *
 * @author Lihai
 * @version 1.0.0
 * @since 2023/7/20
 */
@Slf4j
public class MqttClientPluginImpl implements Plugin {
    final List<ExtractorClassTag<MqttClientSubscribe>>  subscribeClassTags  = new ArrayList<>();
    final List<ExtractorMethodTag<MqttClientSubscribe>> subscribeMethodTags = new ArrayList<>();

    @Override
    public void start(AopContext context) throws Throwable {

        // 查找类上的 MqttClientSubscribe 注解
        Solon.context().beanBuilderAdd(MqttClientSubscribe.class, (clz, beanWrap, anno) -> {
            subscribeClassTags.add(new ExtractorClassTag(clz, beanWrap, anno));
        });
        // 查找方法上的 MqttClientSubscribe 注解
        Solon.context().beanExtractorAdd(MqttClientSubscribe.class, (bw, method, anno) -> {
            subscribeMethodTags.add(new ExtractorMethodTag(bw, method, anno));
        });


        context.lifecycle(Integer.MAX_VALUE, () -> {
            context.beanMake(MqttClientConfiguration.class);
            MqttClientCreator clientCreator = context.getBean(MqttClientCreator.class);

            // MqttClientTemplate init
            IMqttClientConnectListener clientConnectListener  = context.getBean(IMqttClientConnectListener.class);
            MqttClientCustomizer       customizers            = context.getBean(MqttClientCustomizer.class);
            MqttClientTemplate         clientTemplate         = new MqttClientTemplate(clientCreator, clientConnectListener, customizers);
            BeanWrap                   mqttClientTemplateWrap = context.wrap(MqttClientTemplate.class, clientTemplate);
            context.putWrap(MqttClientTemplate.DEFAULT_CLIENT_TEMPLATE_BEAN, mqttClientTemplateWrap);
            context.putWrap(MqttClientTemplate.class, mqttClientTemplateWrap);

            // 客户端 session
            IMqttClientSession clientSession = context.getBean(IMqttClientSession.class);
            clientCreator.clientSession(clientSession);

            // 添加启动时的临时订阅
            subscribeDetector();

            MqttClientProperties properties = context.getBean(MqttClientProperties.class);
            // connect
            if(properties.isEnabled()){
                clientTemplate.connect();
            }
        });
    }

    private void subscribeDetector() {
        subscribeClassTags.stream().forEach(each -> {
            MqttClientSubscribe anno           = each.getAnno();
            MqttClientTemplate  clientTemplate = getMqttClientTemplate(anno);
            String[]            topicFilters   = getTopicFilters(anno);
            IMqttClientMessageListener              iMqttClientMessageListener              = each.getBeanWrap().get();
            clientTemplate.addSubscriptionList(topicFilters, anno.qos(), iMqttClientMessageListener);
        });
        subscribeMethodTags.stream().forEach(each -> {
            MqttClientSubscribe anno           = each.getAnno();
            MqttClientTemplate  clientTemplate = getMqttClientTemplate(anno);
            String[]            topicFilters   = getTopicFilters(anno);
            clientTemplate.addSubscriptionList(topicFilters, anno.qos(), (ctx, topic, message, payload) ->
                    ReflectUtil.invoke(each.getBw().get(), each.getMethod(), topic, payload)
            );
        });
    }

    @Override
    public void stop() throws Throwable {
        MqttClientTemplate clientTemplate = Solon.context().getBean(MqttClientTemplate.class);
        clientTemplate.destroy();
    }

    private MqttClientTemplate getMqttClientTemplate(MqttClientSubscribe anno) {
        return Solon.context().getBean(anno.clientTemplateBean());
    }

    private String[] getTopicFilters(MqttClientSubscribe anno) {
        // 1. 替换 solon cfg 变量
        // 2. 替换订阅中的其他变量
        return Arrays.stream(anno.value())
                .map(Solon.cfg()::getByParse)
                .map(TopicUtil::getTopicFilter)
                .toArray(String[]::new);
    }

    @Data
    @AllArgsConstructor
    private class ExtractorClassTag<T> {
        Class<?> clz;
        BeanWrap beanWrap;
        T        anno;
    }

    @Data
    @AllArgsConstructor
    private class ExtractorMethodTag<T> {
        BeanWrap bw;
        Method   method;
        T        anno;
    }
}
